package com.thingple.usb;

import android.annotation.SuppressLint;
import android.hardware.usb.UsbAccessory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.thingple.usb.manager.DeviceListener;
import com.thingple.usb.manager.UsbDeviceManager;
import com.thingple.usb.manager.UsbManagerWrapper;
import com.thingple.usb.session.UsbSession;
import com.thingple.util.Alert;
import com.thingple.util.Strings;

import org.jetbrains.annotations.NotNull;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class MonitorActivity extends AppCompatActivity {
    private static final String TAG = MonitorActivity.class.getName();

    private BatteryMonitor batteryMonitor;
    private UsbSession session;
    private static final int baudRate = 115200;
    private int usbLostTimes = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_monitor);
        if (getSupportActionBar() != null){
            getSupportActionBar().hide();
        }
        Alert.ctx = this;

        init();
    }

    private void init() {
        initUI();
        initBatteryMonitor();
        listen();
    }

    private void initUI() {
        Button btnLog = findViewById(R.id.btn_log);
        btnLog.setOnClickListener(new LimitedClick(300, v -> logViewControl(btnLog)));
        TextView statusLabel = findViewById(R.id.txt_status);
        statusLabel.setVisibility(View.INVISIBLE);
    }

    private boolean showLogView = false;

    private void logViewControl(Button btn) {
        showLogView = !showLogView;
        View sv = findViewById(R.id.sv);
        View log = findViewById(R.id.scr_log);
        if (showLogView) {
            btn.setText("关闭日志");
            sv.setVisibility(View.INVISIBLE);
            log.setVisibility(View.VISIBLE);
        } else {
            btn.setText("显示日志");
            sv.setVisibility(View.VISIBLE);
            log.setVisibility(View.INVISIBLE);
        }
    }

    private void initBatteryMonitor() {
        batteryMonitor = new BatteryMonitor();
        batteryMonitor.setChargeListener(charging -> refreshLog("充电状态:" + charging));
        batteryMonitor.setLowPowerListener(() -> refreshLog("低电量"));
        batteryMonitor.start(this);
    }

    private void listen() {
        UsbDeviceManager receiver = UsbManagerWrapper.getDeviceManager();
        receiver.setListener(new DeviceListener() {

            @Override
            public void onDeviceAttach(UsbAccessory device) {
                Log.d(TAG, "attach device:" + device.getModel());
//                Alert.msg("attach device:" + device.getModel());
                refreshStatus("attach device:" + device.getModel());
            }

            @Override
            public void onDeviceDetach(UsbAccessory device) {
                Log.d(TAG, "detach:" + device.getModel());
//                Alert.msg("detach:" + device.getModel());
                refreshStatus("detach:" + device.getModel());
            }

            @Override
            public void onDeviceAllowed(UsbAccessory device) {
                Log.d(TAG, "allowed device:" + device.getModel());
//                Alert.msg("allowed device:" + device.getModel());
                refreshStatus("allowed device:" + device.getModel());
                handleDevice(device);
            }
        });
        receiver.registerSpec("Thingple");
        receiver.startMonitor();
//        Alert.msg("scan usb device...");
        refreshStatus("scan usb device...");
        Log.i(TAG, "scan usb device...");
        receiver.scan(); // 扫描已经插入的设备
    }

    @SuppressLint("DefaultLocale")
    private void handleDevice(@NotNull UsbAccessory device) {
        String name = String.format("%s\n[%s:%s]",
                device.getSerial(),
                device.getManufacturer(),
                device.getModel());
        refreshName(name);

        session = UsbManagerWrapper.getDeviceManager().createSession(device, baudRate);
        if (session == null) {
            Log.d(TAG, "创建Usb session失败");
            Alert.msg("创建Usb session失败");
            return;
        }

        session.setErrorListener((e) -> {
            Log.d(TAG, "usb通信中断");
            usbLostTimes++;
            refreshStatus("usb通信中断:" + usbLostTimes + "次 " + e.getMessage());
        });
        session.setStreamUpListener((data, n) -> {
            Log.d(TAG, "自定义处理器:");
            String log = Strings.hexFmt(data).toUpperCase();
            refreshStream(log, true);
        });
        session.setStreamDownListener((data, n, async) -> {
            Log.d(TAG, "自定义处理器:");
            String log = Strings.hexFmt(data).toUpperCase();
            refreshStream(log, false);
        });
        session.setTraceListener(content -> {
            Log.d(TAG, "trace:" + content);
            refreshLog(content);
        });
        session.setAutoResetRework(true);
        session.setReworkEnable(true);

//        autoTx();
        session.start();
    }

    private void refreshName(String name) {
        new Handler(Looper.getMainLooper()).post(() -> {
            TextView v = findViewById(R.id.txt_device);
            v.setText(name);
        });
    }

    @SuppressLint("DefaultLocale")
    private void refreshStatus(String content) {
        new Handler(Looper.getMainLooper()).post(() -> {
            TextView v = findViewById(R.id.txt_status);
            v.setText(String.format("%s", content));
        });
    }
    int lines = 0;
    @SuppressLint("SetTextI18n")
    private void refreshStream(String payload, boolean upstream) {
        lines = lines%23;
        lines++;

        Date now = Calendar.getInstance().getTime();
        String flag = upstream?"<-":"->";
        @SuppressLint("DefaultLocale")
        final String content = String.format("[%s %s]: %s\r\n", flag, fmt(now), payload);
        new Handler(Looper.getMainLooper()).post(() -> {

            ScrollView scrollView = findViewById(R.id.sv);
            TextView textLog = findViewById(R.id.txt_rx);

            if (lines == 1) {
                textLog.setText(content);
            } else {
                textLog.append(content);
            }

            scrollView.post(() -> {
                // TODO
                scrollView.fullScroll(ScrollView.FOCUS_DOWN);
            });
        });
    }

    int logLines = 0;
    @SuppressLint("SetTextI18n")
    private void refreshLog(String payload) {

        @SuppressLint("DefaultLocale")
        final String content = String.format("%d:%s\r\n", logLines, payload);
        new Handler(Looper.getMainLooper()).post(() -> {
            logLines = logLines%23;
            logLines++;
            ScrollView scrollView = findViewById(R.id.scr_log);
            TextView textLog = findViewById(R.id.txt_log);

            if (logLines == 1) {
                textLog.setText(content);
            } else {
                textLog.append(content);
            }

            scrollView.post(() -> {
                // TODO
                scrollView.fullScroll(ScrollView.FOCUS_DOWN);
            });
        });
    }

    @Override
    protected void onDestroy() {
        if (batteryMonitor != null) {
            batteryMonitor.onDestroy();
        }
        UsbManagerWrapper.getDeviceManager().onDestroy();
        if (session != null) {
            session.destroy();
            session = null;
        }
        super.onDestroy();
    }

    DateFormat df;

    @SuppressLint("SimpleDateFormat")
    private String fmt(Date date) {
        if (df == null) {
            df = new SimpleDateFormat("HH:mm:ss");
        }
        return df.format(date);
    }
}